package com.silence.gmall.config;

import com.silence.gmall.config.properties.ThreadPoolProperties;
import io.micrometer.context.ContextExecutorService;
import io.micrometer.context.ContextSnapshotFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author silence
 * @Date 2025-10-30 01:34
 * @Email 792245022@qq.com
 * @Version 1.0
 * @Description 线程池配置
 */
@Configuration
public class ThreadPoolConfig {

    /**
     * 应用名称
     */
    @Value("${spring.application.name:gmall-common-service}")
    private String applicationName;

    /**
     * int corePoolSize,       核心大小
     * int maximumPoolSize,    最大大小（额外开（kat时间不用就要销毁）=最大大小-核心大小 ）
     * long keepAliveTime,     空闲时间
     * TimeUnit unit,          时间单位
     * BlockingQueue<Runnable> workQueue,    排队队列
     * ThreadFactory threadFactory,          线程工厂
     * RejectedExecutionHandler handler      拒绝策略：
     * <p>
     * 如果线程数量已经达到最大，而且队列满了。新任务再进来，利用拒绝策略进行拒绝；
     * 线上提交的任务都是要被执行的，如果线程池没满，就用线程池启动一个异步线程执行（用户感觉快）。
     * 如果线程池满了，让提交任务的当前线程，自己同步运行这个任务即可（用户感觉慢一点）。
     * - @Bean标注的方法。如果有任何参数。这些参数默认都去容器中获取组件
     *
     * @return ThreadPoolExecutor 线程池
     */
    @Bean
    public ExecutorService executorService(ThreadPoolProperties threadPoolProperties) {
        // 线程池
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(threadPoolProperties.getCorePoolSize(),
                threadPoolProperties.getMaximumPoolSize(),
                threadPoolProperties.getKeepAliveTime(),
                TimeUnit.MILLISECONDS,
                new LinkedBlockingDeque<>(threadPoolProperties.getWorkQueueSize()),
                // 线程池中所有的线程都是它new的
                new ThreadFactory() {
                    final AtomicInteger poolNumber = new AtomicInteger(1);

                    @Override
                    public Thread newThread(Runnable r) {
                        // 分布式全线程数量限制：redis.incr(thread-count) < 100000

                        // 利用层层封装完整所有功能
//                        Runnable runnable = new Runnable() {
//                            @Override
//                            public void run() { //根据cpu调度
//
//                            }
//                        };
                        Thread thread = new Thread(() -> {
                            // redis.incr("running...") 任务前置逻辑增强
                            r.run(); // 跑真实任务
                            // redis.decr("running...") 任务后置逻辑增强
                        });
                        thread.setName(applicationName + " - " + poolNumber.getAndIncrement());
                        return thread;
                    }
                },
                // 线上提交的任务都是要被执行的，如果线程池没满，就用线程池启动一个异步线程执行（用户感觉快）。
                // 如果线程池满了，让提交任务的当前线程，自己同步运行这个任务即可（用户感觉慢一点）。
                new ThreadPoolExecutor.CallerRunsPolicy());

        // 使用 Micrometer Context Propagation 包装线程池
        // 这样可以自动传递 traceId、spanId 等追踪上下文
        return ContextExecutorService.wrap(
                threadPoolExecutor,
                () -> ContextSnapshotFactory.builder().build().captureAll());
    }
}
